#include "Includes.h"
#include "dhcp.h"
#include "udp.h"
#include "httputil.h"

#pragma region //============字段=============
static const char *TAG = "UDP通信任务";
#define UDP_BUF_SIZE		(512+2)
static uint8_t rx_buf[UDP_BUF_SIZE * 2];
static uint8_t tx_buf[UDP_BUF_SIZE];
#pragma endregion

#pragma region //============变量=============
extern osSemaphoreId SPI1_CpltSemHandle;
extern osMessageQId UDP_MsgQueueHandle;
extern EEPROM_MSG_STR EEPROM_MSG; /*EEPROM存储信息结构体*/
extern SysState_t SysState; //系统工作状态
#pragma endregion

#pragma region //===============重写方法=================
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == W5500_nINT_Pin)
	{
		osMessagePut(UDP_MsgQueueHandle, 0, 0);
	}
}
/*
********************************************************************************
** 描述: 处理udp接收中断.
********************************************************************************/
void DecodeComProtocol(unsigned char *pFrType/*[I]指向帧类型*/);
uint8_t CheckSum(uint8_t *pByte, uint8_t len);
void ProcessW5500_nINT(uint8_t sn)
{
	uint16_t len;
	if (getSn_IR(SOCK_UDPS) & Sn_IR_RECV)
	{
		setSn_IR(SOCK_UDPS, Sn_IR_RECV); /*清接收中断*/
	}
	if ((len = getSn_RX_RSR(SOCK_UDPS)) > 0)            /*接收到数据*/
	{
		len = recvfrom(SOCK_UDPS, rx_buf, len, remote_ip, &remote_port); /*W5500接收计算机发送来的数据*/
//		sendto(SOCK_UDPS, rx_buf, len, remote_ip, remote_port); /*回传*/
		rx_buf[len] = CheckSum(&rx_buf[1], len - 1);
		DecodeComProtocol(&rx_buf[1]);
	}
}
/*
********************************************************************************
** 描述: 当udp准备好后,处理udp接收的数据并直接返回给远端. 若要实现其它功能则需重写该方法.
********************************************************************************/
uint8_t GetFrameLen(uint8_t type/*[I]帧类型*/);
//打包并向下发送连接确认帧
void PakeLinkAffirmFrAndTx(void);
void ProcessUdpRxTx(void)
{
	osEvent event;
	event = osMessageGet(UDP_MsgQueueHandle, 10); //osWaitForever);
	if (event.status == osEventMessage)
	{
		if (event.value.v != 0)//不是W5500_nINT中断//是打包发送消息
		{
			uint8_t * pTxBuf = (uint8_t*)event.value.p;
			int len = GetFrameLen(pTxBuf[1]);
			len = sendto(SOCK_UDPS, pTxBuf, len, (uint8_t*)remote_ip, remote_port); //Sendto(SOCK_UDPS, buf1, len1, buf2, len2, (uint8_t*)remote_ip, remote_port); /*把帧头+MP3的数据发送给Remote*/
			if (len == 0)
			{
				PRINT("%s: 发送超时!\r\n", TAG);
//				SysState.isTop = 0;
			}
//			else
//			{
//				//进入本程序说明udp连接成功
//				if (SysState.isTop == 0)
//				{
//					SysState.isTop = 1;
//					PakeLinkAffirmFrAndTx();
//				}
//			}
		}
#ifdef W5500_nINT_Pin
		else
		{
			ProcessW5500_nINT(SOCK_UDPS);
		}
#endif // W5500_nINT_Pin
	}
#ifndef W5500_nINT_Pin
	ProcessW5500_nINT(SOCK_UDPS);
#endif // !W5500_nINT_Pin
}
#pragma endregion

#pragma region //===========私有函数=============
#pragma endregion

#pragma region //============方法==============
/*
********************************************************************************
** 描述: udp通信任务.
********************************************************************************/
void UDP_CommTask(void const * argument)
{
	//====局部变量定义
	
	//====初始化
	W5500_Init(&hspi1, SPI1_CpltSemHandle);	//SPI1用于与w5500通信
	if (ip_from != IP_FROM_DHCP)	//本地使用固定ip
	{
		set_w5500_ip(); /*配置IP地址*/
	}
//	osDelay(2000);
	PRINT(" W5500可以和电脑的UDP端口通讯 \r\n");
	PRINT(" W5500的本地端口为:%d \r\n", local_port);
	PRINT(" 远端端口为:%d \r\n", remote_port);
	PRINT(" 连接成功后，PC机发送数据给W5500，W5500将返回对应数据 \r\n");
	
	//====循环体
	for (;;)
	{
		if (ip_from == IP_FROM_DHCP)	//本地使用自动ip
		{
			do_dhcp();
		}
		do_https();	//用http修改配置
		if (reboot_flag == 1)
		{
			HAL_NVIC_SystemReset();
		}
		do_udp();	//使用udp通信,其中在初始化时中断使能
	}
}
#pragma endregion
